﻿using System;

namespace Sigmoid
{
    /// <summary>
    /// Sigmoidfunktionen.
    /// </summary>
    public class Sigmoid
    {
        /// <summary>
        /// Eulersche Sigmoidfunktion von -1 bis +1 und Wendepunkt im 0-Punkt.
        /// 2 / (1 + e<sup>-x</sup>) - 1
        /// </summary>
        /// <param name="x">The input x.</param>
        /// <returns>Funktionsergebnis</returns>
        public static double ESigmoid(double x) {
            return (2.0 / (1.0 + Math.Pow(Math.E, (-x)))) - 1.0;
        }
        /// <summary>
        /// Eulersche Sigmoidfunktion von -N bis +N und Wendepunkt im 0-Punkt.
        /// 2N / (1 + e<sup>-Tx</sup>) - N<para>
        /// T gibt die Steilheit an: Sigmoid(2/T) = 0.76 * N</para>
        /// </summary>
        /// <param name="x">The x.</param>
        /// <param name="N">Limit der Sigmoidfunktion (max = +T, min = -T).</param>
        /// <param name="T">Steilheit der Sigmoidfunktion für die gilt: Sigmoid(2/T) = 0.76 * N </param>
        /// <returns>Funktionsergebnis</returns>
        /// <remarks>Für negatives N, werden die Funktionsergebnise umgekehrt (gespiegelt; von +1 nach -1)</remarks>
        public static double ESigmoid(double x, double N, double T) {
            return N * ((2.0 / (1.0 + Math.Pow(Math.E, (-T * x)))) - 1.0);
        }

        /// <summary>
        /// Eulersche Sigmoidfunktion von -N bis +N und Wendepunkt im 0-Punkt.
        /// 2N / (1 + e<sup>-Tx</sup>) - N<para>
        /// T gibt die Steilheit an: Sigmoid(2/T) = 0.76 * N</para>
        /// </summary>
        /// <param name="x">The x.</param>
        /// <param name="N">Limit der Sigmoidfunktion (max = +T, min = -T).</param>
        /// <param name="T">Steilheit der Sigmoidfunktion für die gilt: Sigmoid(2/T) = 0.76 * N </param>
        /// <param name="xOffset">Verschiebung des Wendepunkts entlang X-Achse</param>
        /// <param name="yOffset">Verschiebung der Funktion entlang Y-Achse</param>
        /// <returns>Funktionsergebnis</returns>
        /// <remarks>Für negatives N, werden die Funktionsergebnise umgekehrt (gespiegelt; von +1 nach -1)</remarks>
        public static double ESigmoid(double x, double N, double T, double xOffset, double yOffset) {
            return N * ((2.0 / (1.0 + Math.Pow(Math.E, (-T * (x - xOffset))))) - 1.0) + yOffset;
        }

        /// <summary>
        /// "Ungenaue" und dafür schnellere Variante der Eulerschen Sigmoidfunktion.
        /// 2 / (1 + e<sup>-x</sup>) - 1
        /// </summary>
        /// <param name="x">The input x.</param>
        /// <returns></returns>
        public static double FastESigmoid(double x) {
            double temp = 1.0 - (x / 16.0);
            temp *= temp; // hoch 2
            temp *= temp; // hoch 4
            temp *= temp; // hoch 8
            temp *= temp; // hoch 16
            return (2.0 / (1.0 + temp)) - 1.0;
        }

        /// <summary>
        /// "Ungenaue" und dafür schnellere Variante der Eulerschen Sigmoidfunktion von -N bis +N und Wendepunkt im 0-Punkt.
        /// 2N / (1 + e<sup>-Tx</sup>) - N<para>
        /// T gibt die Steilheit an: Sigmoid(2/T) = 0.76 * N</para>
        /// </summary>
        /// <param name="x">The x.</param>
        /// <param name="N">Limit der Sigmoidfunktion (max = +T, min = -T).</param>
        /// <param name="T">Steilheit der Sigmoidfunktion für die gilt: Sigmoid(2/T) = 0.76 * N </param>
        /// <returns>Funktionsergebnis</returns>
        /// <remarks>Für negatives N, werden die Funktionsergebnise umgekehrt (gespiegelt; von +1 nach -1)</remarks>
        public static double FastESigmoid(double x, double N, double T) {
            double temp = 1.0 - (T * x / 16.0);
            temp *= temp; // hoch 2
            temp *= temp; // hoch 4
            temp *= temp; // hoch 8
            temp *= temp; // hoch 16
            return N * ((2.0 / (1.0 + temp)) - 1.0);
        }

        /// <summary>
        /// "Ungenaue" und dafür schnellere Variante der Eulerschen Sigmoidfunktion von -N bis +N und Wendepunkt im 0-Punkt.
        /// 2N / (1 + e<sup>-Tx</sup>) - N<para>
        /// T gibt die Steilheit an: Sigmoid(2/T) = 0.76 * N</para>
        /// </summary>
        /// <param name="x">The x.</param>
        /// <param name="N">Limit der Sigmoidfunktion (max = +T, min = -T).</param>
        /// <param name="T">Steilheit der Sigmoidfunktion für die gilt: Sigmoid(2/T) = 0.76 * N </param>
        /// <param name="xOffset">Verschiebung des Wendepunkts entlang X-Achse</param>
        /// <param name="yOffset">Verschiebung der Funktion entlang Y-Achse</param>
        /// <returns>Funktionsergebnis</returns>
        /// <remarks>Für negatives N, werden die Funktionsergebnise umgekehrt (gespiegelt; von +1 nach -1)</remarks>
        public static double FastESigmoid(double x, double N, double T, double xOffset, double yOffset) {
            double temp = 1.0 - (T * (x-xOffset) / 16.0);
            temp *= temp; // hoch 2
            temp *= temp; // hoch 4
            temp *= temp; // hoch 8
            temp *= temp; // hoch 16
            return N * ((2.0 / (1.0 + temp)) - 1.0)  + yOffset;
        }
    }
}
